﻿#region Includes
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Runtime.InteropServices;
#endregion

namespace GingerGL.IO
{
    //------------------------------------------------------------//
    /// <summary>
    /// IO Reader
    /// </summary>
    public class Reader
    {
        //--------------------------------------------------------//
        #region Deserialization
        /// <summary>
        /// Read a List of Objects
        /// </summary>
        public static T[] ReadObjects<T>(Stream fs, int count)
        {
            List<T> obj = new List<T>(count);
            for (int ndex = 0; ndex < count; ndex++)
                obj.Add(ReadObject<T>(fs));
            return obj.ToArray();
        }
        /// <summary>
        /// Reads a Object from File, (Use Marshaling)
        /// </summary>
        public static T ReadObject<T>(Stream fs)
        {
            return Deserialize<T>(GetNextStruct<T>(fs));
        }
        /// <summary>
        /// Reads from file
        /// </summary>
        private static byte[] GetNextStruct<T>(Stream fs)
        {
            byte[] b = new byte[Marshal.SizeOf(typeof(T))];
            fs.Read(b, 0, b.Length);
            return b;
        }
        /// <summary>
        /// Deserialize Object
        /// </summary>
        private static T Deserialize<T>(byte[] rawdatas)
        {
            int rawsize = Marshal.SizeOf(typeof(T));
            if (rawsize > rawdatas.Length)
                throw new FileLoadException("Size of the data did not match data type");
            GCHandle handle = GCHandle.Alloc(rawdatas, GCHandleType.Pinned);
            IntPtr buffer = handle.AddrOfPinnedObject();
            T retobj = (T)Marshal.PtrToStructure(buffer, typeof(T));
            handle.Free();
            return retobj;
        }
        #endregion
        //--------------------------------------------------------//
        #region String Reader
        /// <summary>
        /// Converts Char[] Into String
        /// </summary>
        public static String FixString(char[] input)
        {
            return FixString(new string(input));
        }
        /// <summary>
        /// Converts Byte[] Into String
        /// </summary>
        public static String FixString(byte[] input)
        {
            return FixString(System.Text.Encoding.UTF8.GetString(input));
        }
        /// <summary>
        /// Returns String upto \0
        /// </summary>
        public static String FixString(String input)
        {
            string[] s = input.Split("\0".ToCharArray());
            if (s.Length > 0)
                return s[0];
            return input;
        }
        /// <summary>
        /// Reads a String from a FileStream
        /// </summary>
        public static String ReadString(Stream fs, int count)
        {
            byte[] b = new byte[count];
            fs.Read(b, 0, b.Length); // name
            return FixString(System.Text.Encoding.UTF8.GetString(b));
        }
        #endregion
        //--------------------------------------------------------//
        #region Stream Reader
        /// <summary>
        /// Moves stream to offset position
        /// </summary>
        /// <param name="fs">File Stream</param>
        /// <param name="offset">Offset</param>
        /// <returns>TRUE if completed succussfully</returns>
        static public bool StreamOffset(Stream fs, int offset)
        {
            if (fs.Position == (Int64)offset) return true;              //are we already there?
            if (offset > fs.Length) return false;                       //is offset out of bounds?
            fs.Seek(offset, SeekOrigin.Begin);                          //move to offset
            return true;                                                //successfull
        }
        #endregion
        //--------------------------------------------------------//
    }
    //------------------------------------------------------------//
}
